package org.mozhu.mboot.core.file.cloud.aliyun;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.CompleteMultipartUploadResult;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.UploadFileRequest;
import com.aliyun.oss.model.UploadFileResult;
import org.mozhu.mboot.core.file.cloud.CloudFileService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.List;

public abstract class AliyunCloudFileService implements CloudFileService {

    private Logger LOGGER = LoggerFactory.getLogger(AliyunCloudFileService.class);

    @Override
    public void put(String key, File file) {
        put(key, file.getAbsolutePath());
    }

    @Override
    public void put(String key, String filePath) {
        OSS client = buildOssClient();
        try {
            UploadFileRequest uploadFileRequest = new UploadFileRequest(getBucket(), key);
            // The local file to upload---it must exist.
            uploadFileRequest.setUploadFile(filePath);
            // Sets the concurrent upload task number to 5.
            uploadFileRequest.setTaskNum(5);
            // Sets the part size to 1MB.
            uploadFileRequest.setPartSize(1024 * 1024 * 1);
            // Enables the checkpoint file. By default it's off.
            uploadFileRequest.setEnableCheckpoint(true);

            UploadFileResult uploadResult = client.uploadFile(uploadFileRequest);

            CompleteMultipartUploadResult multipartUploadResult =
                    uploadResult.getMultipartUploadResult();
            LOGGER.debug("Upload file[{}] of key[{}], ETag[{}] successfully", filePath, key, multipartUploadResult.getETag());
        } catch (Throwable e) {
            handleException(e);
        } finally {
            client.shutdown();
        }
    }

    @Override
    public void delete(String key) {
        OSS client = buildOssClient();
        try {
            client.deleteObject(getBucket(), key);
        } catch (Throwable e) {
            handleException(e);
        } finally {
            client.shutdown();
        }
    }

    @Override
    public void batchDelete(List<String> keys) {
        OSS client = buildOssClient();
        try {
            client.deleteObjects(new DeleteObjectsRequest(getBucket()).withKeys(keys));
        } catch (Throwable e) {
            handleException(e);
        } finally {
            client.shutdown();
        }
    }


    protected OSS buildOssClient() {
        return new OSSClientBuilder().build(getEndpoint(), getAccessKeyId(), getAccessKeySecret());
    }

    protected void handleException(Throwable e) {
        if (e instanceof OSSException) {
            OSSException oe = (OSSException) e;
            LOGGER.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.", oe);
            LOGGER.error("Request ID:      " + oe.getRequestId());
            LOGGER.error("Host ID:           " + oe.getHostId());
        } else if (e instanceof ClientException) {
            ClientException ce = (ClientException) e;
            LOGGER.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.", ce);
        } else {
            LOGGER.error("Caught an Exception.", e);
        }
    }

    protected abstract String getEndpoint();

    protected abstract String getAccessKeyId();

    protected abstract String getAccessKeySecret();

    protected abstract String getBucket();

}
